
__author__="joepearson"
__date__ ="$Apr 30, 2011 11:26:20 PM$"

import pypm

class MIDIDevice():
    """
    Class definition allowing one to treat the IAC driver as an object.
    """
    def __init__(self, deviceID=None):
        # Find the OMB IAC driver device.  Ideally, if this doesn't already exist
        # then omb would set this up.  However, I can't find a way of doing this without
        # using Audio MIDI setup.

        if deviceID:
            # If MIDI device ID was given, use that device.
            self.midiOut = pypm.Output(id,0)
            self.name = pypm.GetDeviceInfo(deviceID)[1]
        else:
            # Try to find the IAC Driver OMB device.
            for id in range(pypm.CountDevices()):
                interface,name,input,output,opened = pypm.GetDeviceInfo(id)
                if (name == 'IAC Driver OMB') and output:
                    self.midiOut = pypm.Output(id,0)

        if not self.midiOut:
            # If we still don't have a device, choose the default MIDI
            # output provided by PyPortMIDI
            defaultDevId = pypm.GetDefaultOutputDeviceID()
            self.midiOut = pypm.Output(defaultDevId, 0)
            self.name = pypm.getDeviceInfo(defaultDevId)

        # Finally, if no device ID can be found, then raise an exception.
        if not self.midiOut:
            raise Exception("Could not find a useable MIDI device.  Check Audio MIDI Setup")

    def __str__(self):
        return self.name or None

    def noteOn(self, channel, note, velocity=100):
        """
        Send a note on message.
        """
        assert channel <= 15 and channel >= 0
        # A velocity of 0 is actually a noteOff event!
        assert velocity <= 127 and velocity >=1

        message = 0x90 + channel

        self.midiOut.Write([[[message,note,velocity],pypm.Time()]])

    def noteOff(self, channel, note):
        """
        Send a note off message.

        Note off messages are actually the same as note on messages with zero
        velocity.
        """

        assert channel <= 15 and channel >= 0
        message = 0x90 + channel

        self.midiOut.Write([[[message,note,0],pypm.Time()]])

    def polyKeyPressure(self, channel, note, pressure):
        """
        Send the polyphonic key pressure (aftertouch).
        """
        assert channel <= 15 and channel >= 0
        assert pressure <= 127 and pressure >=0

        message = 0xa0 + channel

        self.midiOut.Write([[[message,note,pressure],pypm.Time()]])

    def ccChange(self, channel, controller, value):
        """
        Send out continuous controller messages.
        """

        assert channel <= 15 and channel >= 0
        assert controller <= 127 and controller >= 0
        assert value <= 127 and value >=0

        message = 0xb0 + channel

        self.midiOut.Write([[[message,controller,value],pypm.Time()]])

    def progChange(self, channel, program):
        """
        Send a program change on the given channel.
        """
        assert channel <= 127 and channel >= 0
        assert program <= 127 and program >=0

        message = 0xc0 + channel

        self.midiOut.Write([[[message, program]]])

    def channelPressure(self, channel, pressure):
        """
        Send out the channel pressure on a given channel.
        """
        assert channel <= 127 and channel >= 0
        assert pressure <= 127 and pressure >=0

        message = 0xd0 + channel

        self.midiOut.Write([[[message, pressure]]])

    def pitchWheel(self, channel, pitch):
        """
        This one is a bit harder.  TODO.
        """

if __name__ == "__main__":

    MIDIDevices = []
    for id in range(pypm.CountDevices()):
        devInfo = pypm.GetDeviceInfo(id)
        if devInfo[3]:
            print id
            newMIDIDevice = MIDIDevice(deviceID=id)
            print MIDIDevice

    print MIDIDevices
